/*
 * This file is part of Space Invaders: Rehash
 * Copyright (C)2007 Vicent Marti (tanoku@gmail.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>

#include "SDL.h"
#include "SDL_ttf.h"
#include "SDL_opengl.h"

#include "game.h"
#include "main.h"
#include "gfx.h"
#include "font_handler.h"
#include "sprites.h"
#include "game_const.h"

bool isPrime( int n );

Alien::Alien( Game *parent, int row, int col, int texid, int id )
{
	m_dead = false;
	m_tex2 = false;
	m_hit = false;
	
	m_shot = false;
	
	m_texId = texid;
	
	m_row = row;
	m_col = col;
	
	m_lifet.start();
	
	m_parent = parent;
	m_boss = false;

	if ( id == -42 )
	{
		m_boss = true;
	}
	else if ( m_parent->getGameRules() & GR_PRIMESHOOTER )
	{
		setNumber(id);
	}
	else if ( m_parent->getGameRules() & GR_COLORSHOOTER )
	{
		m_color = id;
	}
}


void Alien::setNumber( int num )
{
	if ( m_parent->getGameRules() & GR_PRIMESHOOTER )
	{
		if ( num == 1 ) num = 0;
		m_number = num;
		sprintf( m_numberStr, "%d", m_number );
	
		if ( num > 99 )
			m_numberW = 32+16;
		else if ( num > 9 )
			m_numberW = 32;
		else
			m_numberW = 16;
	}
	else
	{
		m_number = 0;
		strcpy(m_numberStr, "");
	}
}

bool Alien::hit( Missile *attacker )
{
	if ( m_boss )
	{
		return true;
	}
	else if ( m_parent->getGameRules() & GR_PRIMESHOOTER )
	{
		if ( m_number > 0 )
		{
			if ( attacker->getNumber() == -1 )
			{
				if ( isPrime(m_number) && m_number > 19 )
				{
					setNumber( 0 );
					m_blinkt.start();
					return true;
				}
				
				return false;
			}
			else if ( attacker->getNumber() > 0 )
			{
				if ( m_number % attacker->getNumber() == 0 )
				{
					setNumber( m_number / attacker->getNumber() );
					m_blinkt.start();
					return true;       
				}
			}
		}
		else
		{
			if ( attacker->getNumber() == 0 )
			{
				m_dead = true;
				return true;
			}
		}
	}
	else if ( m_parent->getGameRules() & GR_COLORSHOOTER )
	{
		if ( attacker->getNumber() == m_color )
		{
			if ( m_parent->getGameRules() & GR_TOUGH_ENEMIES )
			{
				if ( !m_hit )
				{
					if (m_parent->getGameRules() & GR_4_COLORS)
						m_color = 1<<(1+rand()%4);
					else if (m_parent->getGameRules() & GR_6_COLORS)
						m_color = 1<<(1+rand()%6);
					else if (m_parent->getGameRules() & GR_8_COLORS)
						m_color = 1<<(1+rand()%8);
						
					m_hit = true;
					m_blinkt.start();
					return true;
				}
				else
				{
					m_dead = true;
					return true;
				}
		
			}
			else
			{ 
				m_dead = true;
				return true;
			}
		}
		else
		{
			return false;
		}       
	}
	else
	{
		if ( m_parent->getGameRules() & GR_TOUGH_ENEMIES )
		{
			if ( !m_hit )
			{
				m_hit = true;
				m_blinkt.start();
				return true;
			}
			else
			{
				m_dead = true;
				return true;
			}
		
		}
		else
		{ 
			m_dead = true;
			return true;
		}
	}
	
	return false;
}

void Alien::getBounds( SDL_Rect *r )
{
	if ( m_boss )
	{
		r->x = m_x - BOSS_W/2 - 8;
		r->y = m_y - BOSS_H/2 - 8;
		r->w = BOSS_W + 16;
		r->h = BOSS_H;
	}
	else
	{
		r->x = m_x - ALIEN_W/2 - 8;
		r->y = m_y - ALIEN_H/2 - 8;
		r->w = ALIEN_W + 16;
		r->h = ALIEN_H + 16;
		
		if ( ( m_parent->getGameRules() & GR_PRIMESHOOTER ) && m_number > 0 )
		{
			r->h += g_Fonts->get(FONT_ALIEN)->getHeight();
		}
	}
}

void Alien::render()
{
	glEnable2D();
	glEnable( GL_BLEND );
	int tex = (m_tex2)?m_texId:m_texId+1;

	if ( m_boss )
	{	
		glDrawTexuredRect(m_x - BOSS_W/2, m_y - BOSS_H/2, BOSS_W, BOSS_H, g_Textures[tex], 1, 1, 1, true);
	}
	else if ( m_parent->getGameRules() & GR_COLORSHOOTER )
	{
		float r, g, b;
		m_parent->translateColor( m_color, r, g, b );
		glDrawTexuredRect(m_x - ALIEN_W/2, m_y - ALIEN_H/2, ALIEN_W, ALIEN_H, g_Textures[tex], r, g, b, true);
	}
	else
	{
		glDrawTexuredRect(m_x - ALIEN_W/2, m_y - ALIEN_H/2, ALIEN_W, ALIEN_H, g_Textures[tex], 1, 1, 1, true);
	}
	glDisable(GL_BLEND);
	
	if ( ( m_parent->getGameRules() & GR_PRIMESHOOTER ) && m_number > 0 )
	{
		glPrint( FONT_ALIEN, m_x - m_numberW/2, m_y + ALIEN_H/2  + 4, m_numberStr); 
	}
	glDisable2D();
}

void Alien::tick()
{	
	int x, y;
	m_parent->getEnemyPosition(m_row, m_col, x, y);

	if ( m_boss )
	{
		x += 128;
		y += 64;

		if ( m_x >= SCREEN_W/2 && !m_parent->isBossKilling() )
			m_parent->bossKill();
	}
	
	if ( m_x != x )
	{
		m_tex2 = !m_tex2;
		
		if ( !m_boss && !m_shot && ( m_parent->getGameRules() & GR_ENEMIES_DONT_ATTACK ) == 0 && rand()%1000 < 10 )
		{
			printf("Alien shot!\n");
			m_shot = true;
			m_missile_x = m_x;
			m_missile_y = m_y + ALIEN_H/2;
		}
	}

	m_x = x;
	m_y = y;

	this->shootTick();
	
	int bx = m_x, by = m_y + ALIEN_W/2;
	if ( ( m_parent->getGameRules() & GR_PRIMESHOOTER ) && m_number > 0 )
	{
		by += g_Fonts->get(FONT_ALIEN)->getHeight();
	}
	
	if ( by > SCREEN_H-64 )
	{
		m_parent->getPlayer()->hit(200);
	}
	
	SDL_Rect ab;
	for ( int i=0; i<m_parent->getBarrierCount(); ++i )
	{
		if ( m_parent->getBarrierBounds( i, &ab ) )
		{
			if ( bx > ab.x && bx < ab.x+ab.w && by > ab.y && by < ab.y+ab.h )
			{
				m_parent->barrierHit(i, 200);
			}
		}
	}
	
	int ticks = m_blinkt.get_ticks();
	
	if ( ticks > 0 )
	{
		if ( ticks > 120 && ticks <= 500 || ticks > 750 && ticks <= 1000 )
		{
			return;
		}
		else if ( ticks > 1000 )
		{
			m_blinkt.stop();
		}
	}
	
	this->render();
}


void Alien::shootTick()
{
	if ( m_shot )
	{
		SDL_Rect ab;
		m_missile_y += 1;
		
		if ( m_missile_y < 0 || m_missile_y > SCREEN_H || m_missile_x < 0 || m_missile_x > SCREEN_W )
		{
			m_shot = false;
			return;
		}
	
		for ( int i=0; i<m_parent->getBarrierCount(); ++i )
		{
			if ( m_parent->getBarrierBounds( i, &ab ) )
			{
				if ( m_missile_x > ab.x && m_missile_x < ab.x+ab.w && 
				     m_missile_y > ab.y && m_missile_y < ab.y+ab.h )
				{
					m_parent->barrierHit(i, 7 + rand()%7);
					m_shot = false;
					m_parent->newSprite( SPRITE_EXPLOSION_SMALL, m_missile_x, m_missile_y );
					return;
				}
			}
		}
		
		Player *pl = m_parent->getPlayer();
		if ( pl )
		{
			pl->getBounds( &ab );
			if ( m_missile_x > ab.x && m_missile_x < ab.x+ab.w && 
			     m_missile_y > ab.y && m_missile_y < ab.y+ab.h )
			{
				pl->hit(7 + rand()%7);
				m_shot = false;
				m_parent->newSprite( SPRITE_EXPLOSION_SMALL, m_missile_x, m_missile_y );
				return;
			}
		}
		
		glEnable2D();
		glDrawRect( m_missile_x - 2, m_missile_y - 4, 4, 8, 1, 1, 1 );
		glDisable2D();
	}
}
